﻿/*----------------------------------------------------------------
//  <copyright file="OnlineUserProvider.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2024-03-04 14:51</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.Identity
{
    #region "组织机构信息提供者"
    /// <summary>
    /// 组织机构信息提供者
    /// </summary>
    /// <typeparam name="TUser">用户类型</typeparam>
    /// <typeparam name="TUserKey">用户编号类型</typeparam>
    /// <typeparam name="TRole">角色类型</typeparam>
    /// <typeparam name="TRoleKey">角色编号类型</typeparam>
    /// <typeparam name="TOrganization">组织机构类型</typeparam>
    /// <typeparam name="TOrganizationKey">组织机构编号类型</typeparam>
    public class OrganizationProvider<TUser, TUserKey, TRole, TRoleKey, TOrganization, TOrganizationKey> : IOrganizationProvider
        where TUser : UserBase<TUserKey>
        where TUserKey : struct, IEquatable<TUserKey>
        where TRole : RoleBase<TRoleKey, TUserKey>
        where TRoleKey : struct, IEquatable<TRoleKey>
        where TOrganization : OrganizationBase<TOrganizationKey, TUserKey>
        where TOrganizationKey : struct, IEquatable<TOrganizationKey>
    {
        //字段
        private readonly IServiceProvider _serviceProvider;

        #region "构造函数"
        #region "初始化一个组织机构信息提供者的新实例"
        /// <summary>
        /// 初始化一个组织机构信息提供者 <see cref="OrganizationProvider{TUser, TUserKey, TRole, TRoleKey, TOrganization, TOrganizationKey}"/> 的新实例
        /// </summary>
        /// <param name="serviceProvider">服务提供者</param>
        public OrganizationProvider(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        #endregion

        #endregion

        #region "方法"
        #region "获取用户组织机构集合"
        /// <summary>
        /// 获取用户组织机构集合
        /// </summary>
        /// <param name="userId">用户名称</param>
        /// <returns>组织机构集合</returns>
        public virtual async Task<OrganizationDtoSimple[]> GetUserOrganizations(string userId)
        {
            //处理用户组织机构
            UserManager<TUser> userManager = _serviceProvider.GetService<UserManager<TUser>>();
            TUser user = await userManager.FindByIdAsync(userId);
            if (user == null)
            {
                return Array.Empty<OrganizationDtoSimple>();
            }
            RoleManager<TRole> roleManager = _serviceProvider.GetService<RoleManager<TRole>>();
            IList<string> roles = await userManager.GetRolesAsync(user);
            var userOrganizationStore = _serviceProvider.GetService<IUserOrganizationStore<TUser>>();
            var roleOrganizationStore = _serviceProvider.GetService<IRoleOrganizationStore<TRole>>();
            IList<string> userOrganizations = await userOrganizationStore.GetOrganizationsAsync(user);
            var userRoles = roleManager.Roles.Where(o => roles.Contains(o.Name)).ToList();
            foreach (var userRole in userRoles)
            {
                IList<string> roleOrganizationStores = await roleOrganizationStore.GetOrganizationsAsync(userRole);
                userOrganizations = userOrganizations.Union(roleOrganizationStores).ToList();
            }
            //listA.AddRange(listB);//把集合A.B合并
            //List<int> Result = listA.Union(listB).ToList<int>();          //剔除重复项 
            //List<int> Result = listA.Concat(listB).ToList<int>();        //保留重复项
            var queryableOrganizationStore = _serviceProvider.GetService<IQueryableOrganizationStore<TOrganization>>();
            var dtos = queryableOrganizationStore.Organizations.Where(m => userOrganizations.Contains(m.Id.ToString())).Select(o => o.MapTo<TOrganization, OrganizationDtoSimple>()).ToList();

            return dtos.ToArray();
        }
        #endregion
        #region "获取用户组织机构形节点对象集合"
        /// <summary>
        /// 获取用户组织机构形节点对象集合
        /// </summary>
        /// <param name="userId">用户名称</param>
        /// <returns>组织机构集合</returns>
        public virtual async Task<OrganizationTreeNode[]> GetUserOrganizationTreeNodes(string userId)
        {
            var dtos = await GetUserOrganizations(userId);
            if (dtos == null)
            {
                return Array.Empty<OrganizationTreeNode>();
            }
            List<OrganizationNode> nodeList = new();
            var organizationStore = _serviceProvider.GetService<IOrganizationStore<TOrganization>>();
            foreach (var dto in dtos)
            {
                if (dto == null)
                {
                    continue;
                }
                nodeList.AddIfNotExist(dto.ToNode());
                if (dto.Type == OrganizationType.Department && !dto.ParentId.IsMissing())
                {
                    var parentEntity = await organizationStore.FindByIdAsync(dto.ParentId);
                    while (parentEntity != null)
                    {
                        var node = parentEntity.MapTo<TOrganization, OrganizationNode>();
                        if (!nodeList.Exists(o => o.Id == node.Id))
                        {
                            nodeList.Add(node);
                        }
                        //nodeList.AddIfNotExist(node, o => o.Id == node.Id);

                        if (parentEntity.Type == OrganizationType.Department && !parentEntity.ParentId.ToString().IsMissing())
                        {
                            parentEntity = await organizationStore.FindByIdAsync(parentEntity.ParentId.ToString());
                        }
                        else
                        {
                            parentEntity = null;
                        }
                    }
                }
            }
            var treeNodes = nodeList.ToTreeNodes();

            return treeNodes.ToArray();
        }
        #endregion
        #region "获取组织机构信息"
        /// <summary>
        /// 获取用户组织机构集合
        /// </summary>
        /// <param name="organizationId">组织机构编号</param>
        /// <returns>组织机构信息</returns>
        public virtual OrganizationDtoSimple GetOrganizationById(string organizationId)
        {
            if (organizationId.IsMissing())
            {
                return null;
            }
            var queryableOrganizationStore = _serviceProvider.GetService<IQueryableOrganizationStore<TOrganization>>();
            var organization = queryableOrganizationStore.FindById(organizationId);
            if (organization == null)
            {
                return null;
            }
            var dto = organization.MapTo<TOrganization, OrganizationDtoSimple>();
            return dto;
        }
        #endregion

        #region "获取组织机构信息"
        /// <summary>
        /// 获取用户组织机构集合
        /// </summary>
        /// <param name="organizationCode">组织机构编码</param>
        /// <returns>组织机构信息</returns>
        public virtual OrganizationDtoSimple GetOrganizationByCode(string organizationCode)
        {
            if (organizationCode.IsMissing())
            {
                return null;
            }
            var queryableOrganizationStore = _serviceProvider.GetService<IQueryableOrganizationStore<TOrganization>>();
            var organization = queryableOrganizationStore.Organizations.FirstOrDefault(o => o.Code == organizationCode);
            if (organization == null)
            {
                return null;
            }
            var dto = organization.MapTo<TOrganization, OrganizationDtoSimple>();
            return dto;
        }
        #endregion
        #region "根据部门组织编号获取法人组织机构信息"
        /// <summary>
        /// 根据部门组织编号获取法人组织机构信息
        /// </summary>
        /// <param name="departmentId">部门组织机构编号</param>
        /// <returns>组织机构信息</returns>
        public virtual OrganizationDtoSimple GetCorporationOrganizationByDepartmentId(string departmentId)
        {
            OrganizationDtoSimple organizationDto = null;
            if (departmentId.IsMissing())
            {
                return organizationDto;
            }
            var queryableOrganizationStore = _serviceProvider.GetService<IQueryableOrganizationStore<TOrganization>>();
            var departmentOrg = queryableOrganizationStore.FindById(departmentId);
            if (departmentOrg == null)
            {
                return organizationDto;
            }
            var parentOrg = queryableOrganizationStore.Organizations.FirstOrDefault(m => Equals(m.Id, departmentOrg.ParentId));
            while (parentOrg != null)
            {
                if (parentOrg.EnableLogin && (parentOrg.Type == OrganizationType.Virtual || parentOrg.Type == OrganizationType.Corporation))
                {
                    organizationDto = parentOrg.MapTo<TOrganization, OrganizationDtoSimple>();
                    break;
                }
                parentOrg = queryableOrganizationStore.Organizations.FirstOrDefault(m => Equals(m.Id, parentOrg.ParentId));
            }
            return organizationDto;
        }
        #endregion

        #region "获取子级组织机构集合"
        /// <summary>
        /// 获取子级组织机构集合
        /// </summary>
        /// <param name="organizationId">组织机构编号</param>
        /// <returns>子级组织机构集合</returns>
        public virtual OrganizationDtoSimple[] GetChildOrganizations(string organizationId)
        {
            var organizationStore = _serviceProvider.GetService<IOrganizationStore<TOrganization>>();
            var dtos = organizationStore.GetChildOrganizations(organizationId);

            return dtos;
        }
        #endregion
        #region "获取父级组织机构集合"
        /// <summary>
        /// 获取父级组织机构集合
        /// </summary>
        /// <param name="organizationId">组织机构编号</param>
        /// <returns>父级组织机构集合</returns>
        public virtual OrganizationDtoSimple[] GetParentOrganizations(string organizationId)
        {
            var organizationStore = _serviceProvider.GetService<IOrganizationStore<TOrganization>>();
            var dtos = organizationStore.GetParentOrganizations(organizationId);

            return dtos;
        }
        #endregion

        #endregion

    }
    #endregion

}
